﻿using BITUI.Audio;
using SDL2;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;

namespace BITUI
{

    public static class AppFramework
    {
        static AudioSystem _audiosystem;
        public static AudioSystem AudioSystem
        {
            get
            {
                if (_audiosystem == null)
                    _audiosystem = new AudioSystem();
                return _audiosystem;
            }
        }

        public static Window CreateWindow(string title, int tilewidth = 32, int tileheight = 30, WindowOption_ScaleMode scalemode = WindowOption_ScaleMode.AutoTileCount, bool linear = false, float scale = 4.0f)
        {

            Window win = new Window(new WindowOption { title = title, tileWidth = tilewidth, tileHeight = tileheight, scaleMode = scalemode, linear = linear, scale = scale });

            windows[win.id] = win;
            return win;
        }

        public static Window CreateWindow(WindowOption option)
        {

            Window win = new Window(option);

            windows[win.id] = win;
            return win;
        }

        static ConcurrentDictionary<uint, Window> windows = new ConcurrentDictionary<uint, Window>();

        [ThreadStatic]
        static bool bExit;

        [ThreadStatic]
        static Window MainWindow;

        [ThreadStatic]
        static int FrameCount;

        [ThreadStatic]
        static DateTime starttime;
        [ThreadStatic]
        static double timer;

        [ThreadStatic]
        public static double Fps;
        /// <summary>
        /// 启动主循环
        /// </summary>
        /// <param name="mainWindow">主要的窗口，这个窗口关闭时，可以自动退出</param>

        public static void MainLoop(Window mainWindow)
        {
            MainWindow = mainWindow;
            starttime = DateTime.Now;
            timer = 0;
            FrameCount = 0;
            Fps = 0;

            SDL.SDL_StopTextInput();
            bExit = false;
            while (!bExit)
            {
                int dd = SDL.SDL_PollEvent(out SDL.SDL_Event _event);
                if (dd > 0)
                {
                    if (windows.ContainsKey(_event.window.windowID))
                    {
                        if (_event.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
                        {
                            windows[_event.window.windowID].OnEvent(_event.window);
                            if (_event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE)
                            {
                                if (windows.TryRemove(_event.window.windowID, out Window win))
                                {
                                    win.Close();
                                }
                                if (_event.window.windowID == MainWindow.id)
                                {
                                    bExit = true;
                                }
                                continue;
                            }
                            if (_event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED)
                            {

                                windows[_event.window.windowID].OnResize();
                            }
                            if (_event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED)
                            {

                                windows[_event.window.windowID].OnMax(true);
                            }
                            else if (_event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED)
                            {
                                windows[_event.window.windowID].OnMax(false);
                            }
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_MOUSEMOTION)
                        {
                            windows[_event.window.windowID].OnMouseMove(_event.motion.x, _event.motion.y);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN)
                        {
                            windows[_event.window.windowID].OnMouseDown(_event.button.button);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_MOUSEBUTTONUP)
                        {
                            windows[_event.window.windowID].OnMouseUp(_event.button.button);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_MOUSEWHEEL)
                        {
                            windows[_event.window.windowID].OnMouseWheel(_event.wheel.direction, _event.wheel.x, _event.wheel.y);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_KEYDOWN)
                        {
                            windows[_event.window.windowID].OnKey(_event.key.keysym, true);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_KEYUP)
                        {
                            windows[_event.window.windowID].OnKey(_event.key.keysym, false);
                        }
                        else if (_event.type == SDL.SDL_EventType.SDL_TEXTINPUT)
                        {
                            unsafe
                            {
                                List<byte> bts = new List<byte>();
                                for (var i = 0; i < 256; i++)
                                {
                                    var b = _event.text.text[i];
                                    if (b == 0)
                                        break;

                                    bts.Add(b);
                                }
                                var str = System.Text.Encoding.UTF8.GetString(bts.ToArray());
                                windows[_event.window.windowID].OnInput(str);
                                Console.WriteLine("got a input:" + str);
                            }
                        }
                    }

                }
                foreach (var w in windows)
                {
                    w.Value.OnUpdate();
                }
                OnFrameUpdate?.Invoke();

                var newtime = DateTime.Now;
                timer = (newtime - starttime).TotalSeconds;
                FrameCount++;
                if (timer > 1.0)
                {
                    Fps = (FrameCount / timer);
                    timer = 0;
                    FrameCount = 0;
                    starttime = newtime;
                }
                System.Threading.Thread.Sleep(1);
            }
        }
        public static void Exit()
        {
            bExit = true;
        }
        public static event Action OnFrameUpdate;
    }
}
